#include <assert.h>
#include <bitcoin/address.h>
#include <bitcoin/base58.h>
#include <bitcoin/privkey.h>
#include <bitcoin/pubkey.h>
#include <ccan/str/hex/hex.h>
#include <common/setup.h>
#include <common/type_to_string.h>
#include <common/utils.h>
#include <inttypes.h>
#include <stdio.h>
#include "../amount.c"
#define SUPERVERBOSE printf
#include "../funding_tx.c"
#undef SUPERVERBOSE
#include "../key_derive.c"
#include "../type_to_string.c"
#include "../permute_tx.c"
#include "../utxo.c"

/* AUTOGENERATED MOCKS START */
/* Generated stub for fromwire */
const u8 *fromwire(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *copy UNNEEDED, size_t n UNNEEDED)
{ fprintf(stderr, "fromwire called!\n"); abort(); }
/* Generated stub for fromwire_bool */
bool fromwire_bool(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_bool called!\n"); abort(); }
/* Generated stub for fromwire_fail */
void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_fail called!\n"); abort(); }
/* Generated stub for fromwire_node_id */
void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct node_id *id UNNEEDED)
{ fprintf(stderr, "fromwire_node_id called!\n"); abort(); }
/* Generated stub for fromwire_secp256k1_ecdsa_signature */
void fromwire_secp256k1_ecdsa_signature(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
					secp256k1_ecdsa_signature *signature UNNEEDED)
{ fprintf(stderr, "fromwire_secp256k1_ecdsa_signature called!\n"); abort(); }
/* Generated stub for fromwire_sha256 */
void fromwire_sha256(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sha256 *sha256 UNNEEDED)
{ fprintf(stderr, "fromwire_sha256 called!\n"); abort(); }
/* Generated stub for fromwire_tal_arrn */
u8 *fromwire_tal_arrn(const tal_t *ctx UNNEEDED,
		       const u8 **cursor UNNEEDED, size_t *max UNNEEDED, size_t num UNNEEDED)
{ fprintf(stderr, "fromwire_tal_arrn called!\n"); abort(); }
/* Generated stub for fromwire_u16 */
u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u16 called!\n"); abort(); }
/* Generated stub for fromwire_u32 */
u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u32 called!\n"); abort(); }
/* Generated stub for fromwire_u64 */
u64 fromwire_u64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u64 called!\n"); abort(); }
/* Generated stub for fromwire_u8 */
u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u8 called!\n"); abort(); }
/* Generated stub for towire */
void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED)
{ fprintf(stderr, "towire called!\n"); abort(); }
/* Generated stub for towire_bool */
void towire_bool(u8 **pptr UNNEEDED, bool v UNNEEDED)
{ fprintf(stderr, "towire_bool called!\n"); abort(); }
/* Generated stub for towire_node_id */
void towire_node_id(u8 **pptr UNNEEDED, const struct node_id *id UNNEEDED)
{ fprintf(stderr, "towire_node_id called!\n"); abort(); }
/* Generated stub for towire_secp256k1_ecdsa_signature */
void towire_secp256k1_ecdsa_signature(u8 **pptr UNNEEDED,
			      const secp256k1_ecdsa_signature *signature UNNEEDED)
{ fprintf(stderr, "towire_secp256k1_ecdsa_signature called!\n"); abort(); }
/* Generated stub for towire_sha256 */
void towire_sha256(u8 **pptr UNNEEDED, const struct sha256 *sha256 UNNEEDED)
{ fprintf(stderr, "towire_sha256 called!\n"); abort(); }
/* Generated stub for towire_u16 */
void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED)
{ fprintf(stderr, "towire_u16 called!\n"); abort(); }
/* Generated stub for towire_u32 */
void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED)
{ fprintf(stderr, "towire_u32 called!\n"); abort(); }
/* Generated stub for towire_u64 */
void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED)
{ fprintf(stderr, "towire_u64 called!\n"); abort(); }
/* Generated stub for towire_u8 */
void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED)
{ fprintf(stderr, "towire_u8 called!\n"); abort(); }
/* Generated stub for towire_u8_array */
void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED)
{ fprintf(stderr, "towire_u8_array called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */

#if 0
static struct sha256 sha256_from_hex(const char *hex)
{
	struct sha256 sha256;
	if (strstarts(hex, "0x"))
		hex += 2;
	if (!hex_decode(hex, strlen(hex), &sha256, sizeof(sha256)))
		abort();
	return sha256;
}

static struct privkey privkey_from_hex(const char *hex)
{
	struct privkey pk;
	size_t len;
	if (strstarts(hex, "0x"))
		hex += 2;
	len = strlen(hex);
	if (len == 66 && strends(hex, "01"))
		len -= 2;
	if (!hex_decode(hex, len, &pk, sizeof(pk)))
		abort();
	return pk;
}
#endif

int main(int argc, const char *argv[])
{
	common_setup(argv[0]);

	struct bitcoin_tx *input, *funding;
	struct amount_sat fee, change;
	struct pubkey local_funding_pubkey, remote_funding_pubkey;
	struct privkey input_privkey;
	struct pubkey inputkey;
	bool testnet;
	struct utxo utxo;
	const struct utxo **utxomap;
	struct amount_sat funding_sat;
	u16 funding_outnum;
	u8 *subscript, *script;
	struct bitcoin_signature sig;
	struct bitcoin_address addr;
	struct amount_sat tmpamt;
	struct amount_asset asset;

	chainparams = chainparams_for_network("bitcoin");

	/* BOLT #3:
	 *
	 * Block 1 coinbase transaction: 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0100f2052a010000001976a9143ca33c2e4446f4a305f23c80df8ad1afdcf652f988ac00000000
	 */
	input = bitcoin_tx_from_hex(tmpctx,
				    "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0100f2052a010000001976a9143ca33c2e4446f4a305f23c80df8ad1afdcf652f988ac00000000",
				    strlen("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0100f2052a010000001976a9143ca33c2e4446f4a305f23c80df8ad1afdcf652f988ac00000000"));
	input->chainparams = chainparams_for_network("bitcoin");
	assert(input);

	/* BOLT #3:
	 *    Block 1 coinbase privkey: 6bd078650fcee8444e4e09825227b801a1ca928debb750eb36e6d56124bb20e801
	 *    # privkey in base58: cRCH7YNcarfvaiY1GWUKQrRGmoezvfAiqHtdRvxe16shzbd7LDMz
	 */
	if (!key_from_base58("cRCH7YNcarfvaiY1GWUKQrRGmoezvfAiqHtdRvxe16shzbd7LDMz", strlen("cRCH7YNcarfvaiY1GWUKQrRGmoezvfAiqHtdRvxe16shzbd7LDMz"),
			     &testnet, &input_privkey, &inputkey))
		abort();
	assert(testnet);
	printf("* Block 1 coinbase privkey: %s\n",
	       type_to_string(tmpctx, struct privkey, &input_privkey));

	/* BOLT #3:
	 *
	 * The funding transaction is paid to the following pubkeys:
	 *
	 *     local_funding_pubkey: 023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb
	 *     remote_funding_pubkey: 030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c1
	 */
	if (!pubkey_from_hexstr("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb",
				strlen("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb"),
				&local_funding_pubkey))
		abort();
	if (!pubkey_from_hexstr("030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c1",
				strlen("030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c1"),
				&remote_funding_pubkey))
		abort();

	bitcoin_txid(input, &utxo.txid);
	utxo.outnum = 0;
	utxo.amount = AMOUNT_SAT(5000000000);
	utxo.is_p2sh = false;
	utxo.close_info = NULL;
	funding_sat = AMOUNT_SAT(10000000);
	fee = AMOUNT_SAT(13920);

	printf("input[0] txid: %s\n",
	       tal_hexstr(tmpctx, &utxo.txid, sizeof(utxo.txid)));
	printf("input[0] input: %u\n", utxo.outnum);
	printf("input[0] satoshis: %s\n",
	       type_to_string(tmpctx, struct amount_sat, &utxo.amount));
	printf("funding: %s\n",
	       type_to_string(tmpctx, struct amount_sat, &funding_sat));

	utxomap = tal_arr(tmpctx, const struct utxo *, 1);
	utxomap[0] = &utxo;
	if (!amount_sat_sub(&change, utxo.amount, funding_sat)
	    || !amount_sat_sub(&change, change, fee))
		abort();
	funding = funding_tx(tmpctx, chainparams,
			     &funding_outnum, utxomap,
			     funding_sat,
			     &local_funding_pubkey,
			     &remote_funding_pubkey,
			     change,
			     &inputkey, NULL);
	printf("# fee: %s\n",
	       type_to_string(tmpctx, struct amount_sat, &fee));

	asset = bitcoin_tx_output_get_amount(funding, !funding_outnum);
	assert(amount_asset_is_main(&asset));
	tmpamt = amount_asset_to_sat(&asset);
	printf("change: %s\n",
	       type_to_string(tmpctx, struct amount_sat,
			      &tmpamt));

	printf("funding output: %u\n", funding_outnum);

	pubkey_to_hash160(&inputkey, &addr.addr);
	subscript = scriptpubkey_p2pkh(funding, &addr);
	sign_tx_input(funding, 0, subscript, NULL, &input_privkey, &inputkey,
		      SIGHASH_ALL, &sig);

	script = bitcoin_redeem_p2pkh(funding, &inputkey, &sig);
	bitcoin_tx_input_set_script(funding, 0, script);
	printf("funding tx: %s\n",
	       tal_hex(tmpctx, linearize_tx(tmpctx, funding)));

	/* No memory leaks please */
	common_shutdown();
	return 0;
}
